Computer software is often complex. Part of the complexity may arise from the nature of the work a program is designed to perform, e.g., tracking large numbers of real world items or ongoing transactions over hours or longer periods of time, coordinating activities with other complex software, controlling complex hardware, and so on. In almost any real-world use of software, complexity also arises because many details are introduced and should be correctly managed in order to instruct computer hardware how to perform real-world work that is initially described much less precisely in English or another natural language. That is, the transformation from a high-level description to a low-level implementation which is executable by a computer system, inevitably introduces complexity. Even programming language source code, which is more precise than natural languages, is still at a relatively high level and therefore is ambiguous, being open to various understandings and implementations. Source code is transformed into low-level instructions that can be directly executed by computational hardware, with many details being introduced and choices being made during that transformation.
Complexity introduces the all-too-often realized possibility of programming errors, a.k.a. “bugs”. The process of identifying the cause of a bug and attempting to modify a program to remediate or remove the bug's impact is referred to as “debugging”. Specialized software tools which assist debugging are called “debuggers”. The program being debugged is called the “debuggee”.
Debugging is perhaps easiest when a developer can run the debuggee slowly, or at full speed, or pause execution of the debuggee, all at will, and can examine all state information of the debuggee at any point in the debuggee's execution. This is known as “live process debugging”. However, such full access to a debuggee is often not available. For example, the debuggee may be production software that cannot be debugged live without violating service agreements or harming the reputation, security, or finances of an interested party. Unacceptable harms may occur if the live process debuggee is paused for seconds at a time while the developer examines variable values, checks to see which functions were called with which parameter values, reviews the source code, considers possible explanations for the bug, and devises tests that might help identify, remediate, or eliminate the bug.
Accordingly, sometimes state information is recorded as the debuggee executes, to be examined later without substantially pausing the debuggee's execution. For instance, some or all of the memory values pertinent to the debuggee's execution, and operations on those values, may be recorded over time in an execution trace. Some debuggers support use of such a trace to replay the execution of the traced debuggee, without the debuggee being a live process. With some debuggers, the debuggee execution captured in a trace can be replayed in forward or in reverse, thus permitting “time travel”, “reverse”, or “historic” debugging.
Tracing generally slows down the debuggee. Accordingly, advances in tracing a software program's execution while avoiding undue impact on the software's performance help improve the information that is available for use in debugging, and thus will tend to improve the function of debuggee computer systems by facilitating the mediation and eradication of their bugs. To be useful for software programs that rely on asynchronous execution, such advances must be able to continue tracing execution across multiple threads of execution.